package com.ticket.sass.provider.business.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ticket.sass.common.entity.tenant.FilmEntity;
import com.ticket.sass.common.entity.tenant.FilmVersionEntity;
import com.ticket.sass.common.exception.enums.ErrorCode;
import com.ticket.sass.common.exception.exception.BadRequestException;
import com.ticket.sass.common.file.factory.FileServiceFactory;
import com.ticket.sass.common.file.model.FileMode;
import com.ticket.sass.common.file.service.FileService;
import com.ticket.sass.provider.business.FilmBusiness;
import com.ticket.sass.provider.config.AppConfig;
import com.ticket.sass.provider.dto.input.film.*;
import com.ticket.sass.provider.dto.output.film.FilmListOutput;
import com.ticket.sass.provider.dto.output.film.FilmQueryOutput;
import com.ticket.sass.provider.dto.output.film.FilmVersionOutput;
import com.ticket.sass.provider.model.KeyInfoModel;
import com.ticket.sass.provider.service.PageModel;
import com.ticket.sass.provider.service.impl.FilmServiceImpl;
import com.ticket.sass.provider.service.impl.FilmVersionServiceImpl;
import com.ticket.sass.provider.util.CompareUtil;
import com.ticket.sass.provider.util.EscapeUtil;
import com.ticket.sass.provider.util.FileUtil;
import com.ticket.sass.provider.util.ModelUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.modelmapper.TypeToken;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ywb
 * @date 2024-03-28 17:01
 */
@Slf4j
@Service
@AllArgsConstructor
public class FilmBusinessImpl implements FilmBusiness {
    final FileUtil fileUtil;
    final ModelUtil modelUtil;
    final FilmServiceImpl filmService;
    final FilmVersionServiceImpl filmVersionService;
    
    @Override
    public PageModel<FilmListOutput> list(FilmListInput input) {
        IPage<FilmEntity> page = filmService.iPage(input);
        
        // 转换影片列表对象为输出对象
        List<FilmListOutput> outputs = modelUtil.listToList(page.getRecords(), new TypeToken<List<FilmListOutput>>(){}.getType());
        
        Map<Long, List<FilmVersionOutput>> filmVersionsByFilmIds = filmVersionService.getFilmVersionsByFilmIds(outputs.stream().map(FilmListOutput::getId).collect(Collectors.toList()));
        
        outputs.forEach(o -> o.setVersions(filmVersionsByFilmIds.get(o.getId())));

        return new PageModel<>(page.getTotal(), outputs);
    }
    
    @Override
    public void add(FilmAddInput input) {
        if (input.getVersions().size() > 0) {
            List<String> codeList = input.getVersions().stream().map(FilmVersionInput::getCode).collect(Collectors.toList());
            List<String> codeListNotExist = filmVersionService.areCodeListNotExist(codeList);
            if (codeListNotExist.size() > 0) {
                throw new BadRequestException(
                    ErrorCode.RECORD_EXIST,
                    EscapeUtil.errorMessage("version", "以下版本已存在: " + codeListNotExist)
                );
            }
        }
        
        fileUtil.tempFieldPro(input, "cover");
        FilmEntity filmEntity = convertFromInput(input);
        // 将输入对象转换为影片实体对象并保存
        filmService.save(filmEntity);
        
        if (input.getVersions().size() > 0) {
            List<FilmVersionEntity> collect = input.getVersions().stream()
                .map(version -> new FilmVersionEntity(version.getVersion(), version.getCode(), filmEntity.getId()))
                .collect(Collectors.toList());
            
            filmVersionService.saveBatch(collect);
        }
    }
    
    @Override
    public void upd(FilmUpdInput input) {
        // 校验ID
        validateId(input.getId());
        
        // 获取旧版本
        // 获取当前数据库中的发行版本数据
        List<FilmVersionEntity> existingReleaseVersions = filmVersionService.getByMovieId(input.getId());
        List<String> oldCodes = existingReleaseVersions.stream().map(FilmVersionEntity::getCode).collect(Collectors.toList());
        List<String> newCodes = input.getVersions().size() > 0 ?
            input.getVersions().stream().map(FilmVersionInput::getCode).collect(Collectors.toList()) : new ArrayList<>();
        CompareUtil<String> compareUtil = new CompareUtil<>(oldCodes, newCodes);
        // 如果不完全相同则需要判断 新增的是否存在于数据库中
        if (!compareUtil.isSame()){
            List<String> insertCode = compareUtil.getInsert();
            List<String> codeListNotExist = filmVersionService.areCodeListNotExist(insertCode);
            if (codeListNotExist.size() > 0) {
                throw new BadRequestException(
                    ErrorCode.RECORD_EXIST,
                    EscapeUtil.errorMessage("version", "以下版本已存在: " + codeListNotExist)
                );
            }
        }
     
        fileUtil.tempFieldPro(input, "cover");
        // 将输入对象转换为影片实体对象并更新
        FilmEntity filmEntity = convertFromInput(input);
        filmService.updateById(filmEntity);
        if (!compareUtil.isSame()){
            // 执行删除操作
            if (compareUtil.isDel()) {
                filmVersionService.remove(new QueryWrapper<FilmVersionEntity>().eq("film_id", input.getId()).in("code", compareUtil.getDel()));
            }
            
            // 执行新增操作
            if (compareUtil.isInsert()) {
                filmVersionService.saveBatch(
                    input.getVersions().stream()
                        .filter(version ->  compareUtil.getInsert().contains(version.getCode()))
                        .map(version -> new FilmVersionEntity(version.getVersion(), version.getCode(), filmEntity.getId()))
                        .collect(Collectors.toList())
                );
            }
        }
        
        if (compareUtil.isCommon()){
            filmVersionService.updateNamesByCodes(
                input.getVersions().stream()
                .filter(version -> compareUtil.getCommonList().contains(version.getCode()))
                .map(version -> new FilmVersionEntity(version.getVersion(), version.getCode(), filmEntity.getId()))
                .collect(Collectors.toList())
            );
        }
    }
    
    @Override
    public FilmQueryOutput getFilmDetails(FilmQueryInput input) {
        String movieId = extractMovieId(input.getServerUrl());
        // 构建后端请求链接
        String backendUrl = "https://m.maoyan.com/ajax/detailmovie?movieId=" + movieId;
        Document doc;
        JSONObject detailMovieNode;
        String cookie = cookie();
        String userAgent = userAgent();
        try {
            Connection conn = Jsoup.connect(backendUrl)
                .ignoreContentType(true)
                .ignoreHttpErrors(true)
                .cookie("Cookie", cookie)
                .userAgent(userAgent)
                .timeout(30000)
                .method(Connection.Method.GET);
            doc = conn.get();
            detailMovieNode = JSONObject.parseObject(doc.text()).getJSONObject("detailMovie");
     
        
            FilmQueryOutput filmQueryOutput = new FilmQueryOutput();
            
            filmQueryOutput.setName(detailMovieNode.getString("nm"));
            final FileService fileService = FileServiceFactory.getFileService();
            // 获取当前日期
            LocalDate currentDate = LocalDate.now();
            // 将日期格式化成字符串，例如：20240424
            String formattedDate = currentDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            
            FileMode fileMode = fileService.uploadFile(detailMovieNode.getString("img"), "temp/" + formattedDate + "/" + AppConfig.FILE_NAME_MAP.get("movie") + fileName());
            
    
            filmQueryOutput.setCoverModel(new KeyInfoModel(fileMode.getFileName()));
            filmQueryOutput.setReleaseDate(parseToLocalDate(detailMovieNode.getString("rt")));
            filmQueryOutput.setReleaseArea("中国大陆");
            filmQueryOutput.setDirector(detailMovieNode.getString("dir"));
            filmQueryOutput.setActors(splitString(detailMovieNode.getString("star"), ","));
            filmQueryOutput.setTypes(splitString(detailMovieNode.getString("cat"),","));
            filmQueryOutput.setDuration(detailMovieNode.getInteger("dur"));
            filmQueryOutput.setDesc(detailMovieNode.getString("dra"));
            
            filmQueryOutput.setScore(detailMovieNode.getBigDecimal("sc"));
            filmQueryOutput.setVersions(getFilmVersions(detailMovieNode.getString("nm")));
            
            return filmQueryOutput;
        
        } catch (Exception ex) {
            ex.printStackTrace();
            
            throw new BadRequestException(
                ErrorCode.BAD_REQUEST,
                EscapeUtil.errorMessage("serverUrl", "服务地址不正确！")
            );
        }
    }
    
    private String[] splitString(String str, String delimiter) {
        if (str == null || str.isEmpty()) {
            return new String[0];
        }
        return str.split(delimiter);
    }
    
    @Override
    public List<FilmVersionOutput> getVersionDetails(FilmVersionQueryInput input) {
        return getFilmVersions(input.getName());
    }
    
    public static String fileName() {
        String uuid = UUID.randomUUID().toString();
        String randomNum = Integer.toString(new Random().nextInt(10000));
        String hash = Integer.toString(uuid.hashCode() & Integer.MAX_VALUE);
        return hash + randomNum;
    }
    
    public static LocalDate parseToLocalDate(String dateTimeString) {
        if (StrUtil.isEmpty(dateTimeString)) {
            return null;
        }
        
        if (dateTimeString.length() <= 10) {
            try {
                // 解析为日期
                return LocalDate.parse(dateTimeString, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            } catch (DateTimeParseException e) {
                // 解析失败，返回 null 或者抛出异常，视情况而定
                return null;
            }
        } else {
            try {
                // 解析为日期时间
                LocalDateTime localDateTime = LocalDateTime.parse(dateTimeString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                return localDateTime.toLocalDate();
            } catch (DateTimeParseException e) {
                // 解析失败，返回 null 或者抛出异常，视情况而定
                return null;
            }
        }
    }
    
    public static FilmEntity convertFromInput(FilmAddInput input) {
        FilmEntity film = new FilmEntity();
        film.setName(input.getName());
        film.setCover(input.getCover());
        film.setReleaseDate(input.getReleaseDate());
        film.setReleaseArea(input.getReleaseArea());
        
        film.setDirector(input.getDirector());
        if (Objects.nonNull(input.getActors())){
            film.setActor(String.join(",", input.getActors()));
        }
        if (Objects.nonNull(input.getTypes())){
            film.setType(String.join(",", input.getTypes()));
        }
        
        film.setDuration(input.getDuration());
        film.setDesc(input.getDesc());
        film.setScore(input.getScore());
        // 其他属性...
        film.setFromType(input.getFromType());
        film.setFromUrl(input.getFromUrl());
        
        return film;
    }
    
    public static FilmEntity convertFromInput(FilmUpdInput input) {
        FilmEntity film = new FilmEntity();
        film.setId(input.getId());
        film.setName(input.getName());
        film.setCover(input.getCover());
        film.setReleaseDate(input.getReleaseDate());
        film.setReleaseArea(input.getReleaseArea());
        film.setDirector(input.getDirector());
        if (Objects.nonNull(input.getActors())){
            film.setActor(String.join(",", input.getActors()));
        }
        if (Objects.nonNull(input.getTypes())){
            film.setType(String.join(",", input.getTypes()));
        }
        film.setDuration(input.getDuration());
        film.setDesc(input.getDesc());
        film.setScore(input.getScore());
        // 其他属性...
        film.setFromType(input.getFromType());
        film.setFromUrl(input.getFromUrl());
        
        return film;
    }
    
    private String extractMovieId(String filmUrl) {
        // 从 URL 中提取电影 ID，这里假设 URL 的结构是固定的，电影 ID 在最后一个斜杠后面
        return filmUrl.substring(filmUrl.lastIndexOf("/") + 1);
    }
    
    public static String cookie(){
        List<String> list = new ArrayList<>();
        list.add("uuid_n_v=v1; uuid=3EEF66309DB911ECA2C5536560610238FDEC2071AF984EDE9067E0389AD8B5CF; _csrf=55631d692c80b02bb61dfb32714bc1ae9372f1fd07ff51a7836f06c9df4c0f56; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1646617964; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1646617964; _lxsdk_cuid=17f62142fe8c8-06472a96416fdb-37677109-fa000-17f62142fe833; _lxsdk=3EEF66309DB911ECA2C5536560610238FDEC2071AF984EDE9067E0389AD8B5CF; __mta=217413289.1646617965177.1646617965177.1646617965177.1; _lxsdk_s=17f62142ff3-88f-ad-3d1%7C%7C3");
        list.add("uuid_n_v=v1; uuid=E7E11950A8C711EC9D65D9C357197EE1EA669BEC28E849739BA1E37B3FD5C1DE; _lxsdk_cuid=17faa8b0048c8-0dd3f79cf979be-113f645d-fa000-17faa8b0049c8; recentCis=591%3D1200%3D150%3D1; ci=1%2C%E5%8C%97%E4%BA%AC; _lxsdk=E7E11950A8C711EC9D65D9C357197EE1EA669BEC28E849739BA1E37B3FD5C1DE; selectci=true; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1647833711,1649229717; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1649230891; _lxsdk_s=17ffdc05d24-f58-4c-ef1%7C%7C3; __mta=143545610.1647833711261.1649229717213.1649230891611.19");
        list.add("uuid_n_v=v1; uuid=110C5C60A8C111ECB1711118F3C2707DD65716098D87401493BFBDD22F21272C; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1647833711; _lxsdk_cuid=17faa8b0048c8-0dd3f79cf979be-113f645d-fa000-17faa8b0049c8; recentCis=591%3D1200%3D150%3D1; selectci=true; selectci=true; ci=1%2C%E5%8C%97%E4%BA%AC; ci=1%2C%E5%8C%97%E4%BA%AC; ci=1%2C%E5%8C%97%E4%BA%AC; _lxsdk=E7E11950A8C711EC9D65D9C357197EE1EA669BEC28E849739BA1E37B3FD5C1DE; webp=true; featrues=[object Object]; selectci=true");
        list.add("Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1646039076; iuuid=FE86A500A43D11ECB58481232EB51AFCAFC03A976ED34869A132A38611FD8D1E; ci=70%2C%E9%95%BF%E6%B2%99; ci=70%2C%E9%95%BF%E6%B2%99; ci=70%2C%E9%95%BF%E6%B2%99; _lxsdk=722A4090987511ECBBF9A5074C5D0B2A57A12DBEE6ED453C9C4C242911F9E8E6; webp=true");
        list.add("selectci=true; selectci.sig=kdh2HVdzxNAXQp-kYQgChk2a2rw; selectci=true; selectci.sig=kdh2HVdzxNAXQp-kYQgChk2a2rw; ci=1%2C%E5%8C%97%E4%BA%AC; ci.sig=pm2UF_F52zvopd9VUIy6q53v_5w; ci.sig=pm2UF_F52zvopd9VUIy6q53v_5w; ci=1%2C%E5%8C%97%E4%BA%AC; ci.sig=pm2UF_F52zvopd9VUIy6q53v_5w; selectci=true; selectci.sig=kdh2HVdzxNAXQp-kYQgChk2a2rw; uuid_n_v=v1; iuuid=2C0D42E00CE711EFA04C41D48F87DA90E6067D9BA9ED40F084F2CB47C5D6B74F; _lxsdk_cuid=186e41e157fc8-009428fa0242a8-1e525634-384000-186e41e157fc8; __utma=17099173.259908242.1715157426.1715157426.1715157426.1; __utmz=17099173.1715157426.1.1.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; _lxsdk=32B968B00EA111EFA7D89144D35F720D58D84480C7364FF0862D320A29D9B775; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1715137257,1715327098; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1715937647; webp=true; featrues=[object Object]");
        
      
        return RandomUtil.randomEle(list);
    }
    
    public static String userAgent() {
        String[] ua = {
            "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36 OPR/37.0.2178.32",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586",
            "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko",
            "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)",
            "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0)",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 BIDUBrowser/8.3 Safari/537.36",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36 Core/1.47.277.400 QQBrowser/9.4.7658.400",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 UBrowser/5.6.12150.8 Safari/537.36",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36 TheWorld 7",
            "Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/60.0",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.109 Safari/537.36",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
        };
        return RandomUtil.randomEle(ua);
    }
    
    public static List<FilmVersionOutput> getFilmVersions(String filmName) {
        String url = "http://reg.gjdyzjb.cn/filmdownload/w/bimsfilms/api/s";
        
        try {
            // 构建请求参数
            JSONObject requestBody = new JSONObject();
            requestBody.put("showYear", "");
            requestBody.put("type", "");
            requestBody.put("publishVersion", "");
            requestBody.put("filmName", filmName);
            requestBody.put("page", 0);
            requestBody.put("realPage", 1);
            requestBody.put("size", 200);
            
            // 构建 Jsoup 连接
            Connection.Response response = Jsoup.connect(url)
                .method(Connection.Method.POST)
                .ignoreContentType(true)
                .header("Content-Type", "application/json")
                .cookie("Cookie", cookie())
                .userAgent(userAgent())
                .requestBody(requestBody.toJSONString())
                .execute();
            
            // 获取响应文档
            Document doc = response.parse();
            // 解析响应数据
            JSONObject responseData = JSONObject.parseObject(doc.text());
            
            return extractFilmVersions(responseData);
        } catch (IOException ex) {
            System.out.println("Error occurred: " + ex.getMessage());
            return new ArrayList<>();
        }
    }

    
    public static List<FilmVersionOutput> extractFilmVersions(JSONObject responseData) {
        List<FilmVersionOutput> versions = new ArrayList<>();
        JSONArray data = responseData.getJSONArray("data");
        
        for (int i = 0; i < data.size(); i++) {
            JSONObject filmData = data.getJSONObject(i);
            String name = filmData.getString("name");
            String code = filmData.getString("code");
            String timestamp = filmData.getString("publishDate");
            String version = filmData.getString("publishVersionName");
            versions.add(new FilmVersionOutput(name, code, version, timestamp));
        }
        
        return versions;
    }
    
    private void validateId(Long id) {
        if (filmService.isEmpty(id)) {
            throw new BadRequestException(
                ErrorCode.RECORD_NOT_EXIST,
                ErrorCode.RECORD_NOT_EXIST.getReasonPhrase()
            );
        }
    }
}
